{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Plant Monitoring System  \n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Aim\n",
    "\n",
    "* This application notebook uses Grove temperature and Grove water sensors to create a temperature and moisture monitor for plants. The conditions are monitored on the Grove led stick and Grove buzzer. An alert is generated if the water sensor does not detect wetness and if the temperature sensor capture temperature outside set limits. User will be able to change the temperature threshold limits and modify display/signal attributes like led colors and buzzer notes. The notebook can be extended to add a python based emailing system when conditions not conducive for plants are encountered.\n",
    "\n",
    "## References\n",
    "* [Jupyterplot](https://lvwerra.github.io/jupyterplot/)\n",
    "* [Grove water_sensor](https://www.seeedstudio.com/Grove-Water-Sensor.html) \n",
    "* [Grove temperature](https://www.seeedstudio.com/Grove-Temperature-Sensor.html) \n",
    "* [Grove buzzer](https://www.seeedstudio.com/Grove-buzzer.html)   \n",
    "* [Grove Base Shield V2.0](https://www.seeedstudio.com/Base-Shield-V2.html)   \n",
    "\n",
    "## Last revised\n",
    "* 02 April 2021\n",
    "    + Initial version\n",
    "---"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Load _base_ Overlay"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from time import sleep\n",
    "\n",
    "from IPython.display import display, HTML\n",
    "from pynq.overlays.base import BaseOverlay\n",
    "from pynq_peripherals import ArduinoSEEEDGroveAdapter\n",
    "\n",
    "base = BaseOverlay('base.bit')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-box alert-info\">\n",
    "   <h4 class=\"alert-heading\">Library Dependencies </h4>\n",
    "Before proceeding the following libraries must be installed\n",
    "    <ul>\n",
    "        <li> Jupyterplot </li>\n",
    "    </ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "try:\n",
    "    from jupyterplot import ProgressPlot\n",
    "except ImportError:\n",
    "    print(\"This script requires the jupyterplot module \\nInstall with: sudo \"\n",
    "         \"pip3 install jupyterplot\")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## Constructing application with Grove Base Shield V2.0 (Arduino)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-box alert-danger\">\n",
    "    <h4 class=\"alert-heading\">Stop before proceeding further! </h4>\n",
    "     Please make sure you had connected all the sensors before switching the board ON. If the sensors are connected while the board is ON it can cause the system to shutdown. For safe use, you can note down the connections shown below, switch the board OFF make the physical connections and the switch the board back ON.\n",
    "    \n",
    "   <h4 class=\"alert-heading\">Make Physical Connections </h4>\n",
    "    <ul>\n",
    "        <li>Insert the Grove Base Shield into the Arduino connector on the board.</li>\n",
    "        <li>Connect the grove_temperature module to A1 connector of the Grove Base Shield.</li>\n",
    "        <li>Connect the grove_water_sensor module to D5 connector of the Grove Base Shield.</li>\n",
    "        <li>Connect the grove_led_stick module to D7 connector of the Grove Base Shield.</li>\n",
    "        <li> Connect the grove_buzzer module to D6 connector of the Grove Base Shield.</li></ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![](images/dry_arduino.png)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Adapter configuration"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "adapter = ArduinoSEEEDGroveAdapter(base.ARDUINO, D7='grove_led_stick', D5='grove_water_sensor', A1='grove_temperature', D6='grove_buzzer' )"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Define device objects"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "led_stick = adapter.D7\n",
    "water_sensor = adapter.D5\n",
    "temp_sensor = adapter.A1\n",
    "buzzer = adapter.D6"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Construct the Temperature and Moisture Monitor"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "led_colors = [0x0000FF, 0x00E4FF, 0x00FF5C, 0x00FF10, 0x3EFF00, 0xFFFA00,\n",
    "              0xFFC800, 0xFF4600, 0xFF2800, 0xFF0000]  # Blue --> Green --> Red\n",
    "\n",
    "\n",
    "def led_meter(level):\n",
    "    for i in range(level):\n",
    "        led_stick.set_pixel(i, led_colors[i])\n",
    "    for j in range(9, level - 1, -1):\n",
    "        led_stick.set_pixel(j, 0)\n",
    "    led_stick.show()\n",
    "\n",
    "\n",
    "def led_flash(color):\n",
    "    for i in range(10):\n",
    "        led_stick.set_pixel(i, color)\n",
    "    led_stick.show()\n",
    "\n",
    "\n",
    "def enable_buzzer():\n",
    "    if base.switches[0].read():\n",
    "        buzzer.play_note('g', 500)\n",
    "    else:\n",
    "        pass\n",
    "\n",
    "\n",
    "def alert(temp_level, dry):\n",
    "    if not dry:\n",
    "        led_meter(temp_level)\n",
    "    else:\n",
    "        led_flash(0xFF0000)\n",
    "        enable_buzzer()\n",
    "\n",
    "\n",
    "def html_display(temp_value, dry_value):\n",
    "    if dry_value:\n",
    "        color = \"#DC143C\"\n",
    "        status = \" Dry !!\"\n",
    "    else:\n",
    "        color = \"#3CB371\"\n",
    "        status = \" Wet !!\"\n",
    "    return f\"\"\"\n",
    "            <h4>Temperature: <b style=\"color:#00008B\"> {temp_value}°C</b></h4>\n",
    "            <h4>Moisture status: <b style=\"color:{color}\">{status}</b></h4>\n",
    "            <br>\n",
    "           \"\"\""
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "<div class=\"alert alert-box alert-info\">\n",
    "   <h4 class=\"alert-heading\">Notes before running the next cell </h4>\n",
    "    <ul>\n",
    "        <li> Toggle Switch SW0 on the PYNQ-Z2 board is used to enable or disable the alert buzzer.</li>\n",
    "        <li> Since the Water sensor is checking for soil moisture, if the sensor is dry the buzzer will be ON as soon as you run the cell.</li>\n",
    "        <li> You can use a damp tissue and place it on the water sensor with good contact to simulate the soil moisture.</li>\n",
    "        <li> The Temerature sensor is sensitive enough to measure change when a finger is placed on it.</li>\n",
    "    </ul>\n",
    "</div>"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Construct a list of 10 values ranging from room+5°C --> room --> room-5°C\n",
    "limit = 5  # Set limit to +/- 5°C\n",
    "rt = round(temp_sensor.get_temperature(), 2)  # Room temperature\n",
    "high_points = [round((i * (limit / 6) + rt), 2) for i in range(1, 7)]\n",
    "low_points = [round((rt - i * (limit / 6)), 2) for i in range(4, 0, -1)]\n",
    "points = low_points + [rt] + high_points\n",
    "\n",
    "led_meter(4)  # Set Led Stick to room temperature\n",
    "\n",
    "hdisplay = display(HTML(''), display_id=True)  # Initialize display variable\n",
    "\n",
    "pp = ProgressPlot(line_names=[\"Temperature\", \"High Limit\", \"Low Limit\"],\n",
    "    x_lim=[0, 200], y_lim=[rt - 2*limit, rt + 2*limit])\n",
    "\n",
    "for i in range(200):\n",
    "    temperature = round(temp_sensor.get_temperature(), 2)\n",
    "    moisture = water_sensor.is_dry()\n",
    "    hdisplay.update(HTML(html_display(temperature, moisture)))\n",
    "\n",
    "    if rt + limit >= temperature >= rt - limit:\n",
    "        for k, j in enumerate(points):\n",
    "            if (j - (limit / 6)) < temperature < (j + (limit / 6)):\n",
    "                alert(k, moisture)\n",
    "    elif temperature > rt + limit:\n",
    "        enable_buzzer()\n",
    "        alert(10, moisture)\n",
    "    else:\n",
    "        enable_buzzer()\n",
    "        alert(1, moisture)\n",
    "\n",
    "    pp.update([[temperature, rt + limit, rt - limit]])\n",
    "    sleep(0.5)\n",
    "\n",
    "pp.finalize()\n",
    "led_stick.clear()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "Copyright (C) 2021 Xilinx, Inc\n",
    "\n",
    "SPDX-License-Identifier: BSD-3-Clause"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "----"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.6.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
